import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import $ from 'jquery';

function offsetHorizontalAdjust(origin, contentWidth) {
	const winWidth = $('body').innerWidth();
	const target = origin;
	if (target.left < 0) target.left = 0;
	if (target.left + contentWidth > winWidth) target.left = winWidth - contentWidth;
	return target;
}

class Tooltip extends React.Component {
	constructor() {
		super();
		this.state = {};
		this.id = 0;
	}

	componentWillUnmount() {
		this.cleanUp();
	}

	onMouseEnter = () => {
		this.setState({ show: true }, () => {
			if (!this.$holder || !this.$tooltipArrow || !this.$tooltipContent) return;

			this.cleanUp();
			$(this.$tooltipContent).offset({ left: 0, top: 0 });

			this.id = setTimeout(() => {
				const { placement } = this.props;
				const { top: holderTop, left: holderLeft } = $(this.$holder).offset();
				const holderRect = this.$holder.getBoundingClientRect();
				const arrowRect = this.$tooltipArrow.getBoundingClientRect();
				const contentRect = this.$tooltipContent.getBoundingClientRect();
				const { width: holderWidth, height: holderHeight } = holderRect;
				const { width: arrowWidth, height: arrowHeight } = arrowRect;
				const { width: contentWidth, height: contentHeight } = contentRect;

				const halfHolderWidth = holderWidth / 2;
				const halfHolderHeight = holderHeight / 2;
				const halfArrowWidth = arrowWidth / 2;
				const halfArrowHeight = arrowHeight / 2;
				const halfContentWidth = contentWidth / 2;
				const halfContentHeight = contentHeight / 2;

				let contentOffset;
				let arrowOffset;
				switch (placement) {
					case 'bottom':
						arrowOffset = {
							top: holderTop + holderHeight,
							left: (holderLeft + halfHolderWidth) - halfArrowWidth,
						};
						contentOffset = {
							top: arrowOffset.top + arrowHeight,
							left: (holderLeft + halfHolderWidth) - halfContentWidth,
						};
						contentOffset = offsetHorizontalAdjust(contentOffset, contentWidth);
						break;
					case 'left':
						arrowOffset = {
							top: (holderTop + halfHolderHeight) - halfArrowHeight,
							left: holderLeft - arrowWidth,
						};
						contentOffset = {
							top: (holderTop + halfHolderHeight) - halfContentHeight,
							left: arrowOffset.left - contentWidth,
						};
						break;
					case 'right':
						arrowOffset = {
							top: (holderTop + halfHolderHeight) - halfArrowHeight,
							left: holderLeft + holderWidth,
						};
						contentOffset = {
							top: (holderTop + halfHolderHeight) - halfContentHeight,
							left: arrowOffset.left + arrowWidth,
						};
						break;
					default:
						arrowOffset = {
							top: holderTop - arrowHeight,
							left: (holderLeft + halfHolderWidth) - halfArrowWidth,
						};
						contentOffset = {
							top: arrowOffset.top - contentHeight,
							left: (holderLeft + halfHolderWidth) - halfContentWidth,
						};
						contentOffset = offsetHorizontalAdjust(contentOffset, contentWidth);
				}

				$(this.$tooltipArrow).offset(arrowOffset);
				$(this.$tooltipContent).offset(contentOffset);
				this.cleanUp();
				this.setState({ animateShow: true });
			}, 0);
		});
	};

	onMouseLeave = () => {
		this.cleanUp();

		this.setState({ animateShow: false });
		this.id = setTimeout(() => {
			this.setState({ show: false });
		}, 300);
	};

	setHolderRef = (ele) => {
		this.$holder = ele;
	};

	setTooltipArrowRef = (ele) => {
		this.$tooltipArrow = ele;
	};

	setTooltipContentRef = (ele) => {
		this.$tooltipContent = ele;
	};

	cleanUp = () => {
		clearTimeout(this.id);
	};

	render() {
		const { className, keepAlive, inline, title, placement = 'top', children } = this.props;
		const { show, animateShow } = this.state;

		return (
			<div
				className={classNames('bdp-tooltip clearfix', className)} ref={this.setHolderRef}
				style={{ display: inline !== false ? 'inline-block' : 'block' }}
				onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}
			>
				{children}

				{title && (keepAlive || show) ?
					<div className={classNames('bdp-tooltip-container', placement, animateShow && 'bdp-tooltip-show')}>
						<div className="bdp-tooltip-arrow" ref={this.setTooltipArrowRef} />
						<div className="bdp-tooltip-content" ref={this.setTooltipContentRef}>
							<div className="bdp-tooltip-inner">{title}</div>
						</div>
					</div> : null
				}
			</div>
		);
	}
}

Tooltip.propTypes = {
	className: PropTypes.string,
	inline: PropTypes.bool,
	title: PropTypes.node,
	placement: PropTypes.string,
	children: PropTypes.node,
	keepAlive: PropTypes.bool,
};

export default Tooltip;
